"""
图片识别（类别统计）主界面
功能：
1. 上传本地图片
2. 调用后端 /detect 接口进行目标检测
3. 显示检测后的图片及类别统计
4. 查询/清空历史检测结果
"""

import sys
import cv2
import requests
import numpy as np
from collections import Counter
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QTableWidget, QTableWidgetItem, QVBoxLayout, QDialog
import os
from main import load_settings

# -------------------- 全局配置 --------------------
cfg = load_settings()  # 读取 main.py 中的配置
SERVER_URL = f"http://{cfg['ip']}:{cfg['port']}/detect"  # 检测接口
HISTORY_URL = f"http://{cfg['ip']}:{cfg['port']}/history"  # 查询历史接口
CLEAR_HISTORY_URL = f"http://{cfg['ip']}:{cfg['port']}/clear_history"  # 清空历史接口


# -------------------- 线程类 --------------------
class HistoryThread(QtCore.QThread):
    """
    异步拉取历史记录的线程
    信号：
        history_ready(list)  拉取完成后把数据以 list 形式发出
    """
    history_ready = QtCore.pyqtSignal(list)

    def run(self):
        try:
            # 最多拉 1000 条
            resp = requests.get(HISTORY_URL, params={"limit": 1000}, timeout=5)
            # 成功则返回 json 列表，否则返回空列表
            self.history_ready.emit(resp.json() if resp.status_code == 200 else [])
        except Exception:
            # 任何异常都返回空列表
            self.history_ready.emit([])


class ClearHistoryThread(QtCore.QThread):
    """
    异步清空历史记录的线程
    信号：
        clear_done(bool, str)  第一个参数表示是否成功，第二个参数为提示信息
    """
    clear_done = QtCore.pyqtSignal(bool, str)

    def run(self):
        try:
            resp = requests.post(CLEAR_HISTORY_URL, timeout=30)
            success = resp.status_code == 200
            msg = resp.text if not success else "清空成功"
            self.clear_done.emit(success, msg)
        except Exception as e:
            self.clear_done.emit(False, str(e))


# -------------------- 主窗口 --------------------
class ImageWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("图片识别（类别统计）")
        self.resize(1700, 1000)
        self.setStyleSheet("background-color: #fffef8;")

        # 中央部件
        central = QtWidgets.QWidget(self)
        self.setCentralWidget(central)
        main_layout = QtWidgets.QHBoxLayout(central)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(10)

        # ---------- 左侧 ----------
        left_w = QtWidgets.QWidget()
        left_w.setStyleSheet(
                """
                            background: qlineargradient(x1:0, y1:0, x2:0, y2:1,
                                                        stop:0 #c7e6d5, stop:1 #7eb394);
                            border-radius: 10px;
                        """
                )
        left_layout = QtWidgets.QVBoxLayout(left_w)
        left_layout.setContentsMargins(15, 15, 15, 15)
        left_layout.setSpacing(15)

        # 原图显示
        self.label_src = QtWidgets.QLabel("原图")
        self.label_src.setMinimumHeight(200)
        self.label_src.setAlignment(QtCore.Qt.AlignCenter)
        self.label_src.setStyleSheet(
                """
                            background-color: #ffffff; color: #5d8a6a;
                            font-family: "PingFang SC"; font-size: 20px;
                            border: 1px solid #5d8a6a; border-radius: 8px; padding: 10px;
                        """
                )
        self.label_src.setScaledContents(True)
        self.label_src.setSizePolicy(
                QtWidgets.QSizePolicy.Ignored,
                QtWidgets.QSizePolicy.Ignored
                )
        left_layout.addWidget(self.label_src, 2)

        # 按钮公共样式
        btn_qss = """
            QPushButton{
                background-color: #5d8a6a; color: #ffffff;
                font-family: "PingFang SC"; font-size: 18px;
                padding: 10px 20px; border: none; border-radius: 5px;
            }
            QPushButton:hover{ background-color: #4a6f55; }
        """

        # 上传图片
        self.btn_upload = QtWidgets.QPushButton("上传图片")
        self.btn_upload.setStyleSheet(btn_qss)
        self.btn_upload.clicked.connect(self.upload_image)
        left_layout.addWidget(self.btn_upload)

        # 开始识别
        self.btn_detect = QtWidgets.QPushButton("开始识别")
        self.btn_detect.setStyleSheet(btn_qss)
        self.btn_detect.clicked.connect(self.detect_image)
        left_layout.addWidget(self.btn_detect)

        # 查询历史
        self.btn_history = QtWidgets.QPushButton("查询历史")
        self.btn_history.setStyleSheet(btn_qss)
        self.btn_history.clicked.connect(self.show_history)
        left_layout.addWidget(self.btn_history)

        # 清空历史
        self.btn_clear_history = QtWidgets.QPushButton("清空历史记录")
        self.btn_clear_history.setStyleSheet(btn_qss)
        self.btn_clear_history.clicked.connect(self.clear_history)
        left_layout.addWidget(self.btn_clear_history)

        # 返回主界面
        self.btn_back = QtWidgets.QPushButton("返回")
        self.btn_back.setStyleSheet(btn_qss)
        self.btn_back.clicked.connect(self.go_to_main_1)
        left_layout.addWidget(self.btn_back)

        left_layout.addStretch()

        # ---------- 右侧 ----------
        right_w = QtWidgets.QWidget()
        right_layout = QtWidgets.QVBoxLayout(right_w)
        right_layout.setContentsMargins(0, 0, 0, 0)
        right_layout.setSpacing(5)

        # 检测结果图
        self.label_dst = QtWidgets.QLabel("检测结果")
        self.label_dst.setAlignment(QtCore.Qt.AlignCenter)
        self.label_dst.setStyleSheet(
                """
                            background-color: #f2f5f9; color: #5d8a6a;
                            font-family: "PingFang SC"; font-size: 36px;
                            border: 2px dashed #5d8a6a; border-radius: 10px;
                        """
                )
        self.label_dst.setScaledContents(True)
        self.label_dst.setSizePolicy(
                QtWidgets.QSizePolicy.Ignored,
                QtWidgets.QSizePolicy.Ignored
                )
        right_layout.addWidget(self.label_dst, 4)

        # 类别统计
        self.label_class = QtWidgets.QLabel("类别统计：-")
        self.label_class.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.label_class.setWordWrap(True)
        self.label_class.setStyleSheet(
                """
                            background-color: #ffffff; color: #5d8a6a;
                            font-family: "PingFang SC"; font-size: 20px;
                            border: 1px solid #5d8a6a; border-radius: 8px; padding: 10px;
                        """
                )
        right_layout.addWidget(self.label_class, 1)

        main_layout.addWidget(left_w, 1)
        main_layout.addWidget(right_w, 2)

        # 当前选中的图片路径
        self.img_path = None

    # -------------------- 功能函数 --------------------
    def go_to_main_1(self):
        """返回主界面 main.py 的 UI_main_1"""
        try:
            from main import UI_main_1

            self.win = UI_main_1()
            self.close()
        except ImportError:
            QMessageBox.warning(self, "提示", "找不到 main.py，无法返回主界面！")

    def upload_image(self):
        """打开文件对话框选择图片"""
        path, _ = QFileDialog.getOpenFileName(
                self, "选择图片", "",
                "图片文件 (*.jpg *.png *.jpeg *.bmp)"
                )
        if not path:
            return
        self.img_path = path
        pixmap = QtGui.QPixmap(path)
        # 保持宽高比缩放
        self.label_src.setPixmap(
                pixmap.scaled(self.label_src.size(), QtCore.Qt.KeepAspectRatio)
                )

    def detect_image(self):
        """调用后端 /detect 接口进行目标检测"""
        if not self.img_path:
            QMessageBox.warning(self, "提示", "请先上传图片！")
            return
        try:
            # 以 multipart/form-data 形式上传
            with open(self.img_path, 'rb') as f:
                files = {'file': (os.path.basename(self.img_path), f, 'image/jpeg')}
                resp = requests.post(SERVER_URL, files=files, timeout=30)

            if resp.status_code == 200:
                data = resp.json()
                cls_list = data.get("cls_list", [])  # 检测到的类别列表
                img_hex = data.get("img", "")  # 画框后的图片 hex 字符串

                if not img_hex:
                    QMessageBox.warning(self, "解析失败", "服务器未返回图片数据")
                    return

                # 类别统计
                counter = Counter(cls_list)
                stat_text = "类别统计：\n" + \
                            "\n".join([f"{k}：{v}" for k, v in counter.items()]) if counter else "未检测到物体"
                self.label_class.setText(stat_text)

                # 将 hex 字符串转 QPixmap 并显示
                img_arr = np.frombuffer(bytes.fromhex(img_hex), np.uint8)
                img = cv2.imdecode(img_arr, cv2.IMREAD_COLOR)
                rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                h, w, ch = rgb.shape
                qimg = QtGui.QImage(rgb.data, w, h, ch * w, QtGui.QImage.Format_RGB888)
                self.label_dst.setPixmap(
                        QtGui.QPixmap.fromImage(qimg).scaled(
                                self.label_dst.size(), QtCore.Qt.KeepAspectRatio
                                )
                        )
            else:
                QMessageBox.warning(self, "识别失败", f"后端返回错误：{resp.status_code}")
        except Exception as e:
            QMessageBox.warning(self, "错误", str(e))

    # -------------------- 历史相关 --------------------
    def show_history(self):
        """异步拉取历史记录并弹窗显示"""
        self.btn_history.setEnabled(False)  # 防止重复点击
        self.history_thread = HistoryThread()
        self.history_thread.history_ready.connect(self.show_history_table)
        self.history_thread.start()

    def show_history_table(self, rows):
        """将历史数据以表格形式展示"""
        self.btn_history.setEnabled(True)
        if not rows:
            QMessageBox.information(self, "历史", "暂无检测结果")
            return

        dlg = QDialog(self)
        dlg.setWindowTitle("历史检测结果")
        dlg.resize(900, 600)

        # 9 列：ID、时间、文件名、类别、置信度、坐标
        table = QTableWidget(len(rows), 9, dlg)
        table.setHorizontalHeaderLabels(
                ["ID", "时间", "文件名", "类别", "置信度", "x1", "y1", "x2", "y2"]
                )

        for i, row in enumerate(rows):
            for j, key in enumerate(
                    ["id", "timestamp", "img_name", "label", "conf", "x1", "y1", "x2", "y2"]
                    ):
                table.setItem(i, j, QTableWidgetItem(str(row.get(key, ""))))

        table.resizeColumnsToContents()
        layout = QVBoxLayout(dlg)
        layout.addWidget(table)
        dlg.exec_()

    def clear_history(self):
        """异步清空历史记录"""
        reply = QMessageBox.question(
                self, "确认清空",
                "确定要清空所有历史记录吗？此操作不可恢复！",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No
                )
        if reply != QMessageBox.Yes:
            return

        self.btn_clear_history.setEnabled(False)
        self.clear_thread = ClearHistoryThread()
        self.clear_thread.clear_done.connect(self.on_clear_done)
        self.clear_thread.start()

    def on_clear_done(self, success, message):
        """清空历史后的回调"""
        self.btn_clear_history.setEnabled(True)
        if success:
            QMessageBox.information(self, "成功", "历史记录已清空")
        else:
            QMessageBox.warning(self, "失败", f"清空历史记录失败：{message}")


# -------------------- 程序入口 --------------------
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    win = ImageWindow()
    win.show()
    sys.exit(app.exec_())
